package gui;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYDataset;

import parsing.InvalidFunctionException;
import parsing.Parser;
import core.FixedPointIteration;
import core.Method;
import core.Point;
import functions.Function;
import javax.swing.JScrollPane;

public class FixedSolver extends JFrame {
	private JPanel contentPane;
	private JTextField textField;
	private DefaultXYDataset dataset = new DefaultXYDataset();
	private ArrayList<Point> roots = new ArrayList<Point>();
	private int counter = 0;
	private Function fun;
	private int noOfIterations = 50;
	private double precesion = .001;
	private double x1 = -1;
	private double x2 = -1;
	private double initialPoint = 0;
	private File file;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					FixedSolver frame = new FixedSolver();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public FixedSolver() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 753, 491);
		setUndecorated(true);
		contentPane = new JPanel();
		contentPane.setBorder(new TitledBorder(null, "Numerical Beast",
				TitledBorder.CENTER, TitledBorder.ABOVE_TOP, null, null));
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		JFreeChart chart = ChartFactory.createXYLineChart(
				"Finding Fixed Point", // The chart title
				"X", // x axis label
				"Y", // y axis label
				dataset, // The dataset for the chart
				PlotOrientation.VERTICAL, true, // Is a legend required?
				false, // Use tooltips
				false // Configure chart to generate URLs?
				);

		final ChartPanel cp = new ChartPanel(chart);
		cp.setBounds(36, 69, 561, 365);
		contentPane.add(cp);
		
		textField = new JTextField();
		textField.setColumns(10);
		textField.setBounds(36, 27, 711, 31);
		textField.addKeyListener(new KeyListener() {
			@Override
			public void keyTyped(KeyEvent arg0) {
			}

			@Override
			public void keyReleased(KeyEvent arg0) {
			}

			@Override
			public void keyPressed(KeyEvent key) {
				if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
					setBounds(100, 100, 753, 491);
					cp.setLocation(10, 81);
					cp.setSize(583, 358);
				}
			}
		});

		contentPane.add(textField);

		JLabel label = new JLabel("f(x)");
		label.setBounds(10, 20, 33, 24);
		contentPane.add(label);

		JButton button = new JButton("Solve");
		button.setBounds(607, 93, 140, 29);
		contentPane.add(button);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String txt = textField.getText();
				roots = new ArrayList<Point>();
				try {
					fun = new Parser().parse(txt);
				} catch (InvalidFunctionException e1) {
					JOptionPane.showMessageDialog(null, e1.getMessage());
					return;
				}
				Method f;

				f = new FixedPointIteration(noOfIterations, precesion, x1, x2,
						initialPoint);
				long start,end;
				try {
					start = System.nanoTime();
					roots = f.run(fun);
					end = System.nanoTime();
				} catch (Exception e1) {
					JOptionPane.showMessageDialog(null, e1.getMessage());
					return;
				}

				double maxX = Double.MIN_VALUE;
				double minX = Double.MAX_VALUE;

				double step = 0.001;

				for (Point p : roots) {
					minX = Math.min(p.getX(), minX);
					maxX = Math.max(p.getX(), maxX);
				}

				minX -= 1;
				maxX += 1;
				double[][] values = new double[2][(int) ((maxX - minX) / step)];

				int i = 0;
				for (double x = minX; x <= maxX && i < values[0].length; x += step, i++) {
					values[0][i] = x;
					values[1][i] = fun.eval(x);
				}
				dataset.addSeries("Function", values);
				JScrollPane scrollPane = new JScrollPane();
				scrollPane.setBounds(613, 286, 111, 109);
				contentPane.add(scrollPane);

				JList list = new JList();
				scrollPane.setViewportView(list);
				Point[] p = new Point[roots.size()];
				roots.toArray(p);
				list.setListData(p);
				JOptionPane.showMessageDialog(null, "Error Bound " + f.getErrorBound()
						+ "\nNumber Of Iterations " + roots.size()
						+ "\n at " + (end - start) +" ms");

			}
		});

		JButton button_1 = new JButton("Specify Interval");
		button_1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					String s = JOptionPane.showInputDialog(
							"Enter the interval", "x1,x2");
					String[] a = s.split(",");
					x1 = Double.parseDouble(a[0]);
					x2 = Double.parseDouble(a[1]);
				} catch (Exception e1) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null, "Invalid Input");
				}
			}
		});
		button_1.setBounds(607, 134, 140, 29);
		contentPane.add(button_1);

		JButton button_2 = new JButton("Load from file");
		button_2.setBounds(607, 175, 140, 29);
		contentPane.add(button_2);
		button_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				String url = "";
				int returnVal = chooser.showOpenDialog(chooser);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					url = chooser.getSelectedFile().getPath();
				}
				file = new File(url);
			}
		});
		JButton button_3 = new JButton("Specify precision");
		button_3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					String s = JOptionPane.showInputDialog(
							"Enter the precision", "p");
					precesion = Double.parseDouble(s);
				} catch (Exception e1) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null, "Invalid Input");
				}
			}
		});
		button_3.setBounds(607, 216, 140, 29);
		contentPane.add(button_3);

		JButton button_4 = new JButton("Specify Iterations");
		button_4.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					String s = JOptionPane.showInputDialog(
							"Enter the number of iterations", "p");
					noOfIterations = Integer.parseInt(s);
				} catch (Exception e1) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null, "Invalid Input");
				}
			}
		});
		button_4.setBounds(607, 257, 140, 29);
		contentPane.add(button_4);

		JButton button_5 = new JButton("Simulate");
		button_5.setBounds(607, 398, 140, 29);
		contentPane.add(button_5);
		button_5.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					counter = 0;
					double[] d1 = new double[] { roots.get(counter).getX(),
							roots.get(counter).getX() };
					double[] d2 = new double[] { 10, -10 }; // TODO change
					double data1[][] = { d1, d2 };
					dataset.addSeries("t1", data1);
				} catch (Exception ee) {
				}
			}

		});
		JButton button_6 = new JButton(">");
		button_6.setBounds(683, 438, 64, 29);
		contentPane.add(button_6);
		button_6.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					double[] d1 = new double[] { roots.get(counter).getX(),
							roots.get(counter).getX() };
					double[] d2 = new double[] { 10, -10 }; // TODO change
					double data1[][] = { d1, d2 };
					dataset.addSeries("t1", data1);
					if (counter * 2 < roots.size() - 3) {
						counter++;
					}
				} catch (Exception ee) {
				}
			}
		});

		JButton button_7 = new JButton("<");
		button_7.setBounds(607, 438, 64, 29);
		contentPane.add(button_7);
		button_7.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					double[] d1 = new double[] { roots.get(counter).getX(),
							roots.get(counter).getX() };
					double[] d2 = new double[] { 10, -10 }; // TODO change
					double data1[][] = { d1, d2 };
					dataset.addSeries("t1", data1);
					if (counter > 0)
						counter--;
				} catch (Exception ee) {
				}
			}
		});

		
		JButton button_9 = new JButton("Exit");
		button_9.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		button_9.setBounds(145, 439, 93, 29);
		contentPane.add(button_9);

		JButton button_10 = new JButton("Back");
		button_10.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setVisible(false);
				dispose();
				Main.main.setVisible(true);
			}
		});
		button_10.setBounds(30, 439, 93, 29);
		contentPane.add(button_10);

		

		JButton btnInitialPoint = new JButton("Initial Point");
		btnInitialPoint.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					String s = JOptionPane.showInputDialog(
							"Enter the initial point", "p");
					initialPoint = Double.parseDouble(s);
				} catch (Exception e1) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null, "Invalid Input");
				}
			}
		});
		btnInitialPoint.setBounds(607, 297, 140, 29);
		contentPane.add(btnInitialPoint);
		
		JButton btnFullScreen = new JButton("Full Screen");
		btnFullScreen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setExtendedState(JFrame.MAXIMIZED_BOTH);
				cp.setSize(getSize());
				cp.setLocation(0, 0);
				contentPane.setFocusable(true);
			}
		});

		btnFullScreen.setBounds(427, 445, 121, 23);
		contentPane.add(btnFullScreen);
		
	}
}
